package org.ne.banksys.service.serviceImpl;

import jakarta.annotation.Resource;
import org.ne.banksys.entity.Card;
import org.ne.banksys.entity.Trade;
import org.ne.banksys.entity.User;
import org.ne.banksys.mapper.CardMapper;
import org.ne.banksys.mapper.TradeMapper;
import org.ne.banksys.mapper.UserMapper;
import org.ne.banksys.service.BankService;
import org.ne.banksys.utils.MD5Utils;
import org.ne.banksys.utils.RedisLockUtils;
import org.ne.banksys.utils.ThreadLocalUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * @author wey
 * @date 2025/6/16 下午8:39 06
 **/


@Service
public class BankServiceImpl  implements BankService {
    @Resource
    private RedisLockUtils redisLock;
    @Resource
    private CardMapper cardMapper;
    @Resource
    private TradeMapper tradeMapper;
    @Autowired
    private UserMapper userMapper;

    // 存款操作
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deposit(String cardId, String cardPass,BigDecimal amount, String remark) {
        String lockKey = "lock:card:" + cardId;
        String requestId = UUID.randomUUID().toString();

        try {

            // 获取分布式锁（等待3秒，锁持有10秒）
            if (!redisLock.lock(lockKey, requestId, 10)) {
                return ("系统繁忙，请重试");
            }

            Card card = cardMapper.selectById(cardId);


            if (card == null) {
                return ("银行卡不存在");
            }
            Map<String, Object> info = ThreadLocalUtils.get();

            if (!card.getPass().equals( MD5Utils.code( cardPass))) {
                return ("card password mismatch");
            }
            Long id = Long.parseLong(info.get("customerId").toString());
            if (!id.equals(card.getCustomerId())) {
                return ("wrong user");
            }

            if ("是".equals(card.getIsReportLoss())) {
                return "银行卡已挂失";
            }
            // 计算新余额
            BigDecimal newBalance = card.getBalance().add(amount);
//            card.setBalance(BigDecimal.valueOf(newBalance.doubleValue()));
            // 更新数据库
            cardMapper.updateById(card.getCardId(), newBalance);

            // 记录交易
            Trade trade = new Trade();
            trade.setCardId(cardId);
            trade.setTradeType("存款");
            trade.setTradeMoney(amount);
            trade.setTradeDate(new Timestamp(System.currentTimeMillis()));
            trade.setRemark(remark);
            tradeMapper.insert(trade);

            return "操作成功";
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            redisLock.unlock(lockKey, requestId);
        }
    }

    // 取款操作（带余额校验）
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String withdraw(String cardId, String cardPass,BigDecimal amount,String remark) {
        String lockKey = "lock:card:" + cardId;
        String requestId = UUID.randomUUID().toString();

        try {
            if (!redisLock.lock(lockKey, requestId, 10)) {
                return ("系统繁忙，请重试");
            }

            Card card = cardMapper.selectById(cardId);


            if (card == null) {
                return ("银行卡不存在");
            }
            Map<String, Object> info = ThreadLocalUtils.get();

            if (!card.getPass().equals(MD5Utils.code(cardPass))) {
                return ("card password mismatch");
            }
            Long id = Long.parseLong(info.get("customerId").toString());
            if (!id.equals(card.getCustomerId())) {
                return ("wrong user");
            }
            BigDecimal balance = card.getBalance();

            // 余额校验
            if (balance.compareTo(amount) < 0) {
                return ("余额不足");
            }
            if ("是".equals(card.getIsReportLoss())) {
                return "银行卡已挂失";
            }
            // 计算新余额
            BigDecimal newBalance = balance.subtract(amount);
//            card.setBalance(BigDecimal.valueOf(newBalance.doubleValue()));

            // 更新数据库
            cardMapper.updateById(card.getCardId(), newBalance);

            // 记录交易
            Trade trade = new Trade();
            trade.setCardId(cardId);
            trade.setTradeType("取款");
            trade.setTradeMoney(amount);
            trade.setTradeDate(new Timestamp(System.currentTimeMillis()));
            trade.setRemark(remark);
            tradeMapper.insert(trade);

            return "操作成功";
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            redisLock.unlock(lockKey, requestId);
        }
    }

    // 在BankServiceImpl类中添加转账方法
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String transfer(String fromCardId, String toCardId, String cardPass,
                           BigDecimal amount, String remark) {
        // 1. 锁定顺序：按卡号字典序排序避免死锁
        String firstLockKey = fromCardId.compareTo(toCardId) < 0 ?
                "lock:card:" + fromCardId : "lock:card:" + toCardId;
        String secondLockKey = fromCardId.compareTo(toCardId) >= 0 ?
                "lock:card:" + fromCardId : "lock:card:" + toCardId;

        String requestId1 = UUID.randomUUID().toString();
        String requestId2 = UUID.randomUUID().toString();

        try {
            // 2. 按顺序获取分布式锁（锁超时10秒）
            if (!redisLock.lock(firstLockKey, requestId1, 10))
                return "系统繁忙，请重试";

            if (!redisLock.lock(secondLockKey, requestId2, 10)) {
                redisLock.unlock(firstLockKey, requestId1); // 释放第一个锁
                return "系统繁忙，请重试";
            }

            Map<String, Object> info = ThreadLocalUtils.get();
            // 3. 校验转出账户
            Card fromCard = cardMapper.selectById(fromCardId);
            if (fromCard == null) return "转出卡不存在";
            if (!fromCard.getPass().equals(MD5Utils.code(cardPass)))
                return "密码错误";
            if ("是".equals(fromCard.getIsReportLoss()))
                return "转出卡已挂失";
            if (fromCard.getBalance().compareTo(amount) < 0)
                return "余额不足";

            // 4. 校验转入账户
            Card toCard = cardMapper.selectById(toCardId);
            if (toCard == null) {
                return "转入卡不存在";
            }
            if ("是".equals(toCard.getIsReportLoss())) {
                return "转入卡已挂失";
            }
            if (fromCardId.equals(toCardId)) {
                return "不能向本人同名账户转账";
            }



            if (!fromCard.getCustomerId().equals(Long.parseLong(info.get("customerId").toString()))) {
                return "customer id mismatch";
            }
            // 5. 执行转账（原子操作）
            BigDecimal fromNewBalance = fromCard.getBalance().subtract(amount);
            BigDecimal toNewBalance = toCard.getBalance().add(amount);

            cardMapper.updateById(fromCardId, fromNewBalance);
            cardMapper.updateById(toCardId, toNewBalance);

            // 6. 记录双方向交易流水
            Timestamp now = new Timestamp(System.currentTimeMillis());

            Trade outTrade = new Trade(fromCardId, "转出", amount.negate(), now, remark + "->" + toCardId);
            Trade inTrade = new Trade(toCardId, "转入", amount, now, remark + "<-" + fromCardId);

            tradeMapper.insert(outTrade);
            tradeMapper.insert(inTrade);

            return "操作成功";
        } catch (Exception e) {
            throw new RuntimeException("转账异常：" + e.getMessage());
        } finally {
            // 7. 按逆序释放锁
            redisLock.unlock(secondLockKey, requestId2);
            redisLock.unlock(firstLockKey, requestId1);
        }
    }


}
